package com.wzcl.app.service.impl;

import com.alibaba.fastjson.JSON;
import com.wzcl.app.dao.model.ActivitySeckillPromotion;
import com.wzcl.app.dao.repository.ActivitySeckillPromotionRepository;
import com.wzcl.app.model.common.BusinessException;
import com.wzcl.app.model.common.CodeMsg;
import com.wzcl.app.model.common.MyPage;
import com.wzcl.app.model.common.WZCL;
import com.wzcl.app.model.dto.PromotionDto;
import com.wzcl.app.service.ActivitySeckillPromotionService;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Log4j2
@Service
@Transactional
public class ActivitySeckillPromotionServiceImpl implements ActivitySeckillPromotionService {

    @Autowired
    private ActivitySeckillPromotionRepository repository;

    @Override
    public ActivitySeckillPromotion create(PromotionDto promotionDto) {
        ActivitySeckillPromotion activitySeckillPromotion = new ActivitySeckillPromotion();
        activitySeckillPromotion.setActivityId(promotionDto.getActivityId());
        activitySeckillPromotion.setOrderNo(promotionDto.getOrderNo());
        activitySeckillPromotion.setPromotionType(promotionDto.getPromotionType());
        activitySeckillPromotion.setValue(new BigDecimal(promotionDto.getValue()));
        activitySeckillPromotion.setStock(promotionDto.getStock());
        return repository.save(activitySeckillPromotion);
    }

    @Override
    public ActivitySeckillPromotion update(PromotionDto promotionDto) {
        //校验获取
        ActivitySeckillPromotion singlePromotion = getAndCheckById(promotionDto.getId());
        //修改
        singlePromotion.setOrderNo(promotionDto.getOrderNo());
        singlePromotion.setPromotionType(promotionDto.getPromotionType());
        singlePromotion.setValue(new BigDecimal(promotionDto.getValue()));
        singlePromotion.setStock(promotionDto.getStock());
        return repository.save(singlePromotion);
    }

    @Override
    public ActivitySeckillPromotion getById(Integer promotionId) {
        return repository.findById(promotionId).orElse(null);
    }

    @Override
    public ActivitySeckillPromotion deleteById(Integer promotionId) {
        //校验获取
        ActivitySeckillPromotion SeckillPromotion = getAndCheckById(promotionId);
        //删除
        log.info("SeckillPromotion:{} Physical deletion", JSON.toJSONString(SeckillPromotion));
        repository.delete(SeckillPromotion);
        return SeckillPromotion;
    }

    @Override
    public void deleteAllByActivityId(Integer activityId) {
        repository.deleteAllByActivityId(activityId);
    }

    @Override
    public void checkValid(PromotionDto promotionDto) {
        if (promotionDto.getPromotionType() == null) {
            throw new BusinessException(CodeMsg.MUST_BE_NOT_NULL, "缺少秒杀折扣类型");
        }
        if (StringUtils.isBlank(promotionDto.getValue())) {
            throw new BusinessException(CodeMsg.MUST_BE_NOT_NULL, "缺少秒杀对应值");
        }
        if (promotionDto.getStock() == null) {
            throw new BusinessException(CodeMsg.MUST_BE_NOT_NULL, "请设置秒杀商品的库存数");
        }
    }

    @Override
    public void checkConflict(List<ActivitySeckillPromotion> promotionList) {
        if (promotionList != null) {
            if (promotionList.size() > 0) {
                throw new BusinessException(CodeMsg.ACTIVITY_CANNOT_OPERATE, "秒杀活动最多有一个优惠");
            }
        }
    }

    @Override
    public List<ActivitySeckillPromotion> findAllByActivityId(Integer activityId) {
        return repository.findAllByActivityIdOrderByOrderNoDesc(activityId);
    }

    @Override
    public MyPage<ActivitySeckillPromotion> findPage(PromotionDto promotionDto) {
        return new MyPage<>(repository.findAll(getSpecification(promotionDto),promotionDto.getPageable()));
    }

    @Override
    public BigDecimal computePrice(BigDecimal currentPrice, List<ActivitySeckillPromotion> promotions, Map<String,Object> condition) {
        ActivitySeckillPromotion promotion = promotions.get(0);
        if (!(BigDecimal.ZERO.compareTo(currentPrice) < 0)) {
            return BigDecimal.ZERO;
        }
        if (WZCL.ACTIVITY_PROMOTION_TYPE.RATED.equals(promotion.getPromotionType())){
            return promotion.getValue();
        } else if (WZCL.ACTIVITY_PROMOTION_TYPE.AMOUNT.equals(promotion.getPromotionType())) {
            currentPrice = compute(currentPrice, WZCL.OPERATOR_RULE.SUBTRACT, promotion.getValue());
        } else if (WZCL.ACTIVITY_PROMOTION_TYPE.DISCOUNT.equals(promotion.getPromotionType())) {
            currentPrice = compute(currentPrice, WZCL.OPERATOR_RULE.MULTIPLY, promotion.getValue().divide(new BigDecimal("100")));
        }
        return currentPrice;
    }



    @Override
    public ActivitySeckillPromotion getAndCheckById(Integer id) {
        if (id == null) {
            throw new BusinessException(CodeMsg.MUST_BE_NOT_NULL, "缺少秒杀活动ID");
        }
        ActivitySeckillPromotion promotion = getById(id);
        if (promotion == null) {
            throw new BusinessException(CodeMsg.SECKILL_PROMOTION_NOT_EXIST);
        }
        return promotion;
    }


    public Specification<ActivitySeckillPromotion> getSpecification(PromotionDto promotionDto) {
        return new Specification<ActivitySeckillPromotion>() {
            @Override
            public Predicate toPredicate(Root<ActivitySeckillPromotion> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                List<Predicate> predicates = new ArrayList<Predicate>();
                if (promotionDto.getActivityId() != null) {
                    predicates.add(criteriaBuilder.equal(root.get("activityId"), promotionDto.getActivityId()));
                }
                if (promotionDto.getPromotionType() != null) {
                    predicates.add(criteriaBuilder.equal(root.get("promotionType"), promotionDto.getPromotionType()));
                }
                return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
            }
        };
    }

}
